﻿using Expector = TelnetExpect.RegExpector;
//
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using TelnetExpect;
using System.IO;

namespace TelnetTests.ExpectorTests
{
    public class RegExpectorExpectorTests_ReadOneByOne : RegExpectorExpectorTests
    {
        protected override Stream Create_ModifierStream(MemoryStream src)
        {
            return new OneByteAtATimeStream(src);
        }

        public override void TooLongPattern()
        {
            // Too slow (too much output) in one-by-one mode.
        }

    }


    [TestFixture]
    public class RegExpectorExpectorTests
    {
        public RegExpectorExpectorTests()
        {
            TestsBase.EnsureConsoleTraceListener();
        }

        //----
        protected virtual Stream Create_ModifierStream(MemoryStream src)
        {
            return src;
        }

        void DoTest(string input, string match, bool expectMatch)
        {
            using (MultiTest mt = new MultiTest(this, input)) {
                mt.DoTest(match, expectMatch);
            }
        }

        protected class MultiTest : IDisposable
        {
            Expector xp;
            MemoryStream dst;
            int testCount;

            public MultiTest(RegExpectorExpectorTests this_, string input)
            {
                byte[] inputB = Encoding.ASCII.GetBytes(input);
                MemoryStream src0 = new MemoryStream(inputB, false);
                Stream src = this_.Create_ModifierStream(src0);
                dst = new MemoryStream();
                PairStream conn = new PairNoCanSeekStream(src, dst);
                xp = this_.Create_Expector(conn);
            }

            public void DoTest(string match, bool expectMatch)
            {
                ++testCount;
                try {
                    xp.Expect(match);
                    Assert.IsTrue(expectMatch, "Expected NO match, but did. " + " -- " + testCount);
                } catch (EndOfStreamException) {
                    Assert.IsFalse(expectMatch, "Expected match, but did NOT." + " -- " + testCount);
                }
                Assert.AreEqual(0, dst.Length, "written count");
            }

            #region IDisposable Members

            public void Dispose()
            {
                Dispose(true);
            }

            protected virtual void Dispose(bool disposing)
            {
            }

            #endregion
        }

        //--------
        void Create_Expector(string input, out Expector xp, out MemoryStream dst)
        {
            if (input == null)
                input = string.Empty;
            byte[] inputB = Encoding.ASCII.GetBytes(input);
            MemoryStream src0 = new MemoryStream(inputB, false);
            Stream src = /*this_.Create_ModifierStream(*/src0;
            dst = new MemoryStream();
            PairStream conn = new PairNoCanSeekStream(src, dst);
            xp = Create_Expector(conn);
        }

        protected virtual Expector Create_Expector(Stream conn)
        {
            RegExpector xp = new RegExpector(conn);
            return xp;
        }

        //--------
        [Test]
        public void Match_All()
        {
            DoTest("abcd", "abcd", true);
        }

        [Test]
        public void Match_Middle()
        {
            DoTest("xxxabcdyyy", "abcd", true);
        }

        [Test]
        public void Match_End()
        {
            DoTest("abcdyyy", "abcd", true);
        }

        //--------
        [Test]
        public void NoMatch_A()
        {
            DoTest("bcd", "abcd", false);
        }

        [Test]
        public void NoMatch_B()
        {
            DoTest("acd", "abcd", false);
        }

        [Test]
        public void NoMatch_D()
        {
            DoTest("abc", "abcd", false);
        }

        [Test]
        public void NoMatch_A_xx()
        {
            DoTest("xxbcd", "abcd", false);
        }

        [Test]
        public void NoMatch_B_xx()
        {
            DoTest("xxacd", "abcd", false);
        }

        [Test]
        public void NoMatch_D_xx()
        {
            DoTest("xxabc", "abcd", false);
        }

        [Test]
        public void NoMatch_A_xx_yy()
        {
            DoTest("xxbcdyy", "abcd", false);
        }

        [Test]
        public void NoMatch_B_xx_yy()
        {
            DoTest("xxacdyy", "abcd", false);
        }

        [Test]
        public void NoMatch_D_xx_yy()
        {
            DoTest("xxabcyy", "abcd", false);
        }

        [Test]
        public void NoMatch_A_yy()
        {
            DoTest("bcdyy", "abcd", false);
        }

        [Test]
        public void NoMatch_B_yy()
        {
            DoTest("acdyy", "abcd", false);
        }

        [Test]
        public void NoMatch_D_yy()
        {
            DoTest("abcyy", "abcd", false);
        }

        //--------
        [Test]
        public virtual void TooLongPattern()
        {
            try {
                DoTest(new string('a', 1025) + "x", new string('a', 2000), false);
                Assert.Ignore("That's odd it should have failed.....");
            } catch (InvalidOperationException ex) {
                Assert.AreEqual("We're gonna need a bigger buffer!!!!!!!", ex.Message);
            }
        }

        //--------
        [Test]
        public void mtMatch_All()
        {
            using (MultiTest mt = new MultiTest(this, "abcd")) {
                mt.DoTest("abcd", true);
            }
        }

        [Test]
        public void mtMatch_AllTwice_NonContiguous()
        {
            using (MultiTest mt = new MultiTest(this, "abcdxxabcd")) {
                mt.DoTest("abcd", true);
                mt.DoTest("abcd", true);
            }
        }

        [Test]
        public void mtMatch_AllTwice_Contiguous()
        {
            using (MultiTest mt = new MultiTest(this, "abcdabcd")) {
                mt.DoTest("abcd", true);
                mt.DoTest("abcd", true);
            }
        }

        [Test]
        public void mtMatch_AllTwice_Contiguous_NotAtEnd()
        {
            using (MultiTest mt = new MultiTest(this, "abcdabcd"
                    + new string('x', 1020))) {
                mt.DoTest("abcd", true);
                mt.DoTest("abcd", true);
            }
        }

        //--------
        [Test]
        public void Timeout()
        {
            Expector xp;
            MemoryStream dst;
            //
            dst = new MemoryStream();
            FooStream conn = new FooStream(dst);
            xp = Create_Expector(conn);
            //
            xp.ExpectTimeout = new TimeSpan(0, 0, 2);
            TimeSpan to = xp.ExpectTimeout;
            Assert.AreEqual(2, to.TotalSeconds, "TotalSeconds");
            //
            string input;
            byte[] inputB;
            input = "abcdwxy";
            inputB = Encoding.ASCII.GetBytes(input);
            conn.SendToRead(inputB);
            xp.Expect("abcd");
            //
            int start = Environment.TickCount;
            try {
                xp.Expect("wxyZ");
                Assert.Fail("should have thrown!");
            } catch {
                int period = Environment.TickCount - start;
                Assert.Greater(period, 1500, "should wait two seconds" /*we check for 1.5 */);
                Assert.Less(period, 2500, "should wait not much more that two seconds" /*we check for 2.5 */);
            }
        }

        //--------
        [Test]
        public void SendLine()
        {
            Expector xp;
            MemoryStream dst;
            Create_Expector(null, out xp, out dst);
            xp.SendLine("exit");
            byte[] expected = {
                (byte)'e', (byte)'x', (byte)'i', (byte)'t', 0x0D, 0x0A,
            };
            TestsBase.Assert_Buffers_AreEqual(expected, dst, null);
        }

        [Test]
        public void SendLine2()
        {
            Expector xp;
            MemoryStream dst;
            Create_Expector(null, out xp, out dst);
            xp.SendLine("dir");
            xp.SendLine("exit");
            byte[] expected = {
                (byte)'d', (byte)'i', (byte)'r', 0x0D, 0x0A,
                (byte)'e', (byte)'x', (byte)'i', (byte)'t', 0x0D, 0x0A,
            };
            TestsBase.Assert_Buffers_AreEqual(expected, dst, null);
        }

    }
}
